#include "kernel/syscall/user.h"
#include "kernel/syscall/unistd.h"


extern "C" void user_level_function(void);


extern "C" unsigned long do_exit(unsigned long code)
{
	LOG_ERROR("exit task is running,arg:%#018lx\n",code);
	while (1)
    {
        /* code */
    }
    
}


extern "C" uint64_t do_execve(StackFrame * regs,char* name)
{
   
    uint64_t ret = 0;
    uint64_t codeStartAddr = 0x800000;
    uint64_t stackStartAddr = 0xa00000;
    uint64_t brkStartAddr = 0xc00000;

    Page * p = NULL;
    int64_t pos = 0;
    uint64_t* tmp = NULL;
    uint64_t* virtualAddrss = NULL;
    
    regs->DS = USER_DS;
    regs->ES = USER_DS;
    regs->OLDSS = USER_DS;
    regs->CS = USER_CS;
	regs->R10 = 0x800000;	//RIP
	regs->R11 = 0xa00000;	//RSP
	regs->RAX = 1;	



    if(current->flags & PF_VFORK)
    {

        current->mm = new taskmemory();

        current->mm->pgd = (pml4t_t*)Virt_To_Phy(MEMORY->kmalloc(PAGE_4K_SIZE,0));

        memset(Phy_To_Virt(current->mm->pgd),0,PAGE_4K_SIZE);
       
        memcpy(Phy_To_Virt( TASKMANAGER->init_task[getAPICID()]->mm->pgd) + 256,Phy_To_Virt(current->mm->pgd) + 256,PAGE_4K_SIZE / 2);


    }
    

    tmp = Phy_To_Virt((uint64_t *)((uint64_t)current->mm->pgd & (~ 0xfffUL)) + ((codeStartAddr >> PAGE_GDT_SHIFT) & 0x1ff));
    if(*tmp == NULL){
        virtualAddrss = (uint64_t*)MEMORY->kmalloc(PAGE_4K_SIZE,0);
        memset(virtualAddrss,0,PAGE_4K_SIZE);
	    set_mpl4t(tmp,mk_mpl4t(Virt_To_Phy(virtualAddrss),PAGE_USER_GDT));

    }

	tmp = Phy_To_Virt((uint64_t *)(*tmp & (~ 0xfffUL)) + ((codeStartAddr >> PAGE_1G_SHIFT) & 0x1ff));

    if(*tmp == NULL){

        virtualAddrss = (uint64_t*)MEMORY->kmalloc(PAGE_4K_SIZE,0);
        memset(virtualAddrss,0,PAGE_4K_SIZE);
        set_pdpt(tmp,mk_pdpt(Virt_To_Phy(virtualAddrss),PAGE_USER_Dir));


    }

    uint64_t* tmpTemp = tmp;
	tmp = Phy_To_Virt((uint64_t *)(*tmp & (~ 0xfffUL)) + ((codeStartAddr >> PAGE_2M_SHIFT) & 0x1ff));
    if(*tmp == NULL){

        p = MEMORY->alloc_pages(ZONE_NORMAL,1,PG_PTable_Maped);
        set_pdt(tmp,mk_pdt(p->PHY_address,PAGE_USER_Page));

    }
    

    tmp = Phy_To_Virt((uint64_t *)(*tmpTemp & (~ 0xfffUL)) + ((stackStartAddr >> PAGE_2M_SHIFT) & 0x1ff));
    if(*tmp == NULL){

        p = MEMORY->alloc_pages(ZONE_NORMAL,1,PG_PTable_Maped);
        set_pdt(tmp,mk_pdt(p->PHY_address,PAGE_USER_Page));

    }
     

    __asm__ __volatile__ ("movq	%0,	%%cr3	\n\t"::"r"(current->mm->pgd):"memory");

;
    flush_tlb();

	if(!(current->flags & PF_KTHREAD))
		current->addr_limit = TASK_SPACE_SIZE;

	current->mm->start_code = codeStartAddr;
	current->mm->end_code = 0;
	current->mm->start_data = 0;
	current->mm->end_data = 0;
	current->mm->start_rodata = 0;
	current->mm->end_rodata = 0;
	current->mm->start_bss = 0;
	current->mm->end_bss = 0;
	current->mm->start_brk = 0;
	current->mm->end_brk = 0;
	current->mm->start_stack = stackStartAddr;
    current->mm->start_brk = brkStartAddr;
    current->mm->end_brk = brkStartAddr;
    
    TASKMANAGER->exitFiles(current);

    current->flags &= ~PF_VFORK;


    File* filp = TASKMANAGER->openExecFile(name);
    
    if(filp)
        LOG_INFO("Find file\n");
  
    memset((void *)0x800000,0,PAGE_2M_SIZE);

    ret = filp->read((char*)codeStartAddr,filp->dentry->dirInode->fileSize,&pos);
	return ret;
}




extern "C" void user_level_printf(char* str)
{
	long error = 0;

	__asm__	__volatile__	(	\
                    "pushq %%r10 \n\t" \
                    "pushq %%r11 \n\t" \
                    "leaq	sysexit_return_address_1(%%rip),	%%r10	\n\t"
					"movq	%%rsp,	%%r11		\n\t"
					"sysenter			\n\t"
					"sysexit_return_address_1:	\n\t"
                    "xchgq %%rdx,%%r10 \n\t" \
                    "xchgq %%rcx,%%r11 \n\t" \
                    "popq %%r11 \n\t" \
                    "popq %%r10 \n\t" \
					:"=a"(error)
                    :"0"(__NR_putstring),"D"(str)
                    :"memory");	

   

}


extern "C" uint64_t open(char* str,int64_t mode){


    long error = 0;
	
	__asm__	__volatile__(	\
                    "pushq %%r10 \n\t" \
                    "pushq %%r11 \n\t" \
                    "leaq	sysexit_return_address_2(%%rip),	%%r10	\n\t"
					"movq	%%rsp,	%%r11		\n\t"
					"sysenter			\n\t"
					"sysexit_return_address_2:	\n\t"
                    "xchgq %%rdx,%%r10 \n\t" \
                    "xchgq %%rcx,%%r11 \n\t" \
                    "popq %%r11 \n\t" \
                    "popq %%r10 \n\t" \
					:"=a"(error)
                    :"0"(__NR_OPEN),"D"(str),"S"(mode) 
                    :"memory");	

	// LOG_ERROR("error:number:%d",error);
  

}


extern "C" uint64_t close(uint64_t fd){


    long error = 0;
	
	// register int fd asm("r15") = 0;

	__asm__	__volatile__(	\
                    "pushq %%r10 \n\t" \
                    "pushq %%r11 \n\t" \
                    "leaq	sysexit_return_address_3(%%rip),	%%r10	\n\t"
					"movq	%%rsp,	%%r11		\n\t"
					"sysenter			\n\t"
					"sysexit_return_address_3:	\n\t"
                    "xchgq %%rdx,%%r10 \n\t" \
                    "xchgq %%rcx,%%r11 \n\t" \
                    "popq %%r11 \n\t" \
                    "popq %%r10 \n\t" \
					:"=a"(error)
                    :"0"(__NR_CLOSE),"D"(fd)
                    :"memory");	

  
}


extern "C" uint64_t read(uint64_t fd,uint8_t* buffer,uint64_t bytes){


    long error = 0;
	
	// register int fd asm("r15") = 0;
    
	__asm__	__volatile__(	\
                    "pushq %%r10 \n\t" \
                    "pushq %%r11 \n\t" \
                    "leaq	sysexit_return_address_4(%%rip),	%%r10	\n\t"
					"movq	%%rsp,	%%r11		\n\t"
					"sysenter			\n\t"
					"sysexit_return_address_4:	\n\t"
                    "xchgq %%rdx,%%r10 \n\t" \
                    "xchgq %%rcx,%%r11 \n\t" \
                    "popq %%r11 \n\t" \
                    "popq %%r10 \n\t" \
					:"=a"(error)
                    :"0"(__NR_READ),"D"(fd),"S"(buffer),"d"(bytes)
                    :"memory");	

  
}

extern "C" uint64_t write(uint64_t fd,uint8_t* buffer,uint64_t bytes){


    long error = 0;
	
	// register int fd asm("r15") = 0;

	__asm__	__volatile__(	\
                    "pushq %%r10 \n\t" \
                    "pushq %%r11 \n\t" \
                    "leaq	sysexit_return_address_5(%%rip),	%%r10	\n\t"
					"movq	%%rsp,	%%r11		\n\t"
					"sysenter			\n\t"
					"sysexit_return_address_5:	\n\t"
                    "xchgq %%rdx,%%r10 \n\t" \
                    "xchgq %%rcx,%%r11 \n\t" \
                    "popq %%r11 \n\t" \
                    "popq %%r10 \n\t" \
					:"=a"(error)
                    :"0"(__NR_WRITE),"D"(fd),"S"(buffer),"d"(bytes)
                    :"memory");	

  
}


extern "C" uint64_t lseek(uint64_t fd,uint64_t offset,uint64_t origin){


    long error = 0;
	
	// register int fd asm("r15") = 0;

	__asm__	__volatile__(	\
                    "pushq %%r10 \n\t" \
                    "pushq %%r11 \n\t" \
                    "leaq	sysexit_return_address_6(%%rip),	%%r10	\n\t"
					"movq	%%rsp,	%%r11		\n\t"
					"sysenter			\n\t"
					"sysexit_return_address_6:	\n\t"
                    "xchgq %%rdx,%%r10 \n\t" \
                    "xchgq %%rcx,%%r11 \n\t" \
                    "popq %%r11 \n\t" \
                    "popq %%r10 \n\t" \
					:"=a"(error)
                    :"0"(__NR_LSEEK),"D"(fd),"S"(offset),"d"(origin)
                    :"memory");	

}


extern "C" void* brk(uint64_t size){


    long error = 0;
	
	// register int fd asm("r15") = 0;

	__asm__	__volatile__(	\
                    "pushq %%r10 \n\t" \
                    "pushq %%r11 \n\t" \
                    "leaq	sysexit_return_address_7(%%rip),	%%r10	\n\t"
					"movq	%%rsp,	%%r11		\n\t"
					"sysenter			\n\t"
					"sysexit_return_address_7:	\n\t"
                    "xchgq %%rdx,%%r10 \n\t" \
                    "xchgq %%rcx,%%r11 \n\t" \
                    "popq %%r11 \n\t" \
                    "popq %%r10 \n\t" \
					:"=a"(error)
                    :"0"(__NR_BRK),"D"(size)
                    :"memory");	

}


extern "C" void* reboot(uint64_t cmd,void* arg){


    long error = 0;
	
	// register int fd asm("r15") = 0;

	__asm__	__volatile__(	\
                    "pushq %%r10 \n\t" \
                    "pushq %%r11 \n\t" \
                    "leaq	sysexit_return_address_8(%%rip),	%%r10	\n\t"
					"movq	%%rsp,	%%r11		\n\t"
					"sysenter			\n\t"
					"sysexit_return_address_8:	\n\t"
                    "xchgq %%rdx,%%r10 \n\t" \
                    "xchgq %%rcx,%%r11 \n\t" \
                    "popq %%r11 \n\t" \
                    "popq %%r10 \n\t" \
					:"=a"(error)
                    :"0"(__NR_REBOOT),"D"(cmd),"S"(arg)
                    :"memory");	

}
